/*
 * geometry.h
 *
 *  Created on: 2012-12-7
 *      Author: shane
 */

#ifndef GEOMETRY_H_
#define GEOMETRY_H_
#include<vector>
#include<cmath>
#include "EME_exception.h"
namespace EME
{
///Exceptions for geometry class
class EME_geometry_logic_error: public EME_logic_error
{
public:
	inline explicit EME_geometry_logic_error(const std::string&s, unsigned int code) :
	EME_logic_error(s, code){};
};
class geo_point2{
public:
	double x;
	double y;
	inline geo_point2():x(0.),y(0.){};
	inline geo_point2(const double& x_in,const double& y_in):x(x_in),y(y_in){};
	inline geo_point2(const geo_point2& b):x(b.x),y(b.y){};
	inline static double p2pdistance(const geo_point2& a,const geo_point2& b){
		return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
	};
	inline static double Multiply(const geo_point2& p1,const geo_point2& p2,const geo_point2& p0){
		return ( (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y) );
	};
	~geo_point2(){};
};
class geo_line2{
public:
	geo_point2 begin;
	geo_point2 end;
	inline geo_line2():begin(geo_point2()),end(geo_point2()){};
	inline geo_line2(const geo_line2& b):begin(b.begin),end(b.end){};
	inline geo_line2(const geo_point2& begin_in,const geo_point2& end_in):begin(begin_in),end(end_in){};
	inline double distance(){
		return geo_point2::p2pdistance(begin,end);
	};
	static bool Intersect(const geo_line2 L1,const geo_line2 L2);
	bool containPoint(const geo_point2& p);
};
enum geo_type
{
	rectangle, polygon, ellipse
};
class geo_object
{
protected:
	friend class pattern;
	double xmin;
	double xmax;
	double ymin;
	double ymax;
	double area;
public:
	geo_object();
	geo_object(const geo_object& b);
	virtual geo_type get_type()=0;
	virtual int inside(const geo_point2& p)=0;
	virtual ~geo_object(){};
};
///for rectangles and squares only, if this is used, then regular meshing may be recommended for faster computation
class geo_rectangle: public geo_object
{
public:
	///generated by two points, whatever which one is the first
	geo_rectangle(const geo_point2& a,const geo_point2&b);
	geo_rectangle(const geo_rectangle& b);
	virtual geo_type get_type();
	virtual int inside(const geo_point2& p);
	~geo_rectangle(){};
};
///for polygons, including triangles
class geo_polygon: public geo_object
{
public:

	///judge whether the polygon is simple or not
	bool issimple();
	///signed return, positive for counter-clockwise, negative for clockwise
	double area_of_polygon();
	bool isccwise();
	/// 1 for inside, 0 for outside, 2 for on the edge.
	virtual int inside(const geo_point2& p);
	virtual geo_type get_type();
	geo_polygon(const std::vector<geo_point2>& vertexs_in);
	geo_polygon(const geo_polygon& b);
	~geo_polygon(){};
private:
	std::vector<geo_point2> vertexs;
};
class geo_ellipse: public geo_object{
private:
	geo_point2 center;
	double a;
	double b;
public:
	geo_ellipse(const geo_point2& c,const double& r);
	geo_ellipse(const geo_point2& c,const double& a_in,const double& b_in);
	geo_ellipse(const geo_ellipse& B);
	virtual int inside(const geo_point2& p);
	virtual geo_type get_type();
	~geo_ellipse(){}
};
}

#endif /* GEOMETRY_H_ */
